package com.tianshi.order.service.impl;

import com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.handler.codec.socksx.v4.Socks4CommandRequest;

public class SnowFlake {
    private final long datacenterId;  // 数据中心ID（可配置）
    private final long machineId;     // 机器ID（可配置）
    private long sequence = 0L;       // 序列号
    private long lastTimestamp = -1L; // 上次时间戳

    // 起始时间戳 (2020-01-01)
    private final long twepoch = 1577836800000L;

    // 机器ID所占位数
    private final long workerIdBits = 5L;
    // 数据中心ID所占位数
    private final long datacenterIdBits = 5L;
    // 序列号所占位数
    private final long sequenceBits = 12L;

    // 机器ID最大值
    private final long maxWorkerId = -1L ^ (-1L << workerIdBits);
    // 数据中心ID最大值
    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);

    // 机器ID左移位数
    private final long workerIdShift = sequenceBits;
    // 数据中心ID左移位数
    private final long datacenterIdShift = sequenceBits + workerIdBits;
    // 时间戳左移位数
    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
    // 序列号掩码
    private final long sequenceMask = -1L ^ (-1L << sequenceBits);

    // 私有构造方法
    private SnowFlake(long datacenterId, long machineId) {
        if (datacenterId > maxDatacenterId || datacenterId < 0) {
            throw new IllegalArgumentException("Datacenter ID must be between 0 and " + maxDatacenterId);
        }
        if (machineId > maxWorkerId || machineId < 0) {
            throw new IllegalArgumentException("Machine ID must be between 0 and " + maxWorkerId);
        }
        this.datacenterId = datacenterId;
        this.machineId = machineId;
    }

    // 静态内部类，持有单例实例
    private static class SnowFlakeHolder {
        private static final SnowFlake INSTANCE = new SnowFlake(1, 1); // 默认数据中心ID和机器ID
    }

    // 获取单例实例
    public static SnowFlake getInstance() {
        return SnowFlakeHolder.INSTANCE;
    }

    // 生成下一个ID
    public synchronized long nextId() {
        long timestamp = System.currentTimeMillis();

        // 处理时钟回拨
        if (timestamp < lastTimestamp) {
            throw new RuntimeException("Clock moved backwards. Refusing to generate id for " +
                    (lastTimestamp - timestamp) + " milliseconds");
        }

        if (lastTimestamp == timestamp) {
            sequence = (sequence + 1) & sequenceMask;
            if (sequence == 0) {
                // 序列号用尽，等待下一毫秒
                timestamp = tilNextMillis(lastTimestamp);
            }
        } else {
            // 时间戳改变，重置序列号
            sequence = 0L;
        }

        lastTimestamp = timestamp;

        // 生成最终ID
        return ((timestamp - twepoch) << timestampLeftShift) |
                (datacenterId << datacenterIdShift) |
                (machineId << workerIdShift) |
                sequence;
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = System.currentTimeMillis();
        while (timestamp <= lastTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }
}